package pri.hillchen.std.concurrent.chapter12;

import java.util.concurrent.Semaphore;

/**
 * @author:hillchen
 * @DESCRIPTION:
 * @Date: Created in 12:55 2018/2/12 0012.
 * 自定义有界阻塞队列
 */
public class BoundedBuffer<T> {
    /**
     * 可用元素信号量，队列尺寸，通过该信号量来判断本队列是否有数据可以读取
     */
    private final Semaphore availableItems;
    /**
     * 可用空间信号量，用来表示本队列还可以添加多少元素，通过该信号量来判断本队列是否已满
     */
    private final Semaphore availableSpaces;

    /**
     * 队列数据添加元素指针，指向队尾
     */
    private int putPosition = 0;
    /**
     * 队列数据读取指针，指向对头
     */
    private int takePosition = 0;

    /**
     * 元素列表
     */
    private final T[] items;

    /**
     * 根据队列容量来初始化队列,初始化可用元素信号量为0，可用空间信号量等于capacity
     * @param capacity
     */
    public BoundedBuffer(int capacity) {
        this.items = (T[]) new Object[capacity];
        this.availableItems = new Semaphore(0);
        this.availableSpaces = new Semaphore(capacity);
    }

    /**
     * 判断队列是否为空
     * @return
     */
    public boolean isEmpty(){
        return this.availableItems.availablePermits() == 0;
    }

    /**
     * 判断队列是否已满
     * @return
     */
    public boolean isFull(){
        return this.availableSpaces.availablePermits() == 0;
    }

    public void put(T element) throws InterruptedException {
        availableSpaces.acquire();
        insertEle(element);
        availableItems.release();
    }

    public T take() throws InterruptedException {
        availableItems.acquire();
        T ele = getEle();
        availableSpaces.release();
        return ele;
    }

    private synchronized void insertEle(T element){
        int i = putPosition;
        items[i] = element;
        putPosition = (++i == items.length) ? 0 : i;
    }
    private synchronized  T getEle(){
        int i = takePosition;
        T ele = items[i];
        takePosition = (++i == items.length) ? 0 : i;
        return ele;
    }
}
